package CreateRole

import (
	"encoding/json"
	codecs "sanguo/codec/cs"
	"sanguo/node/common/GlobalConstData"
	"sanguo/node/common/asynwrap"
	"sanguo/node/common/db"
	"sanguo/node/common/transaction"
	"sanguo/node/common/wordsFilter"
	"sanguo/node/node_game"
	"sanguo/node/node_game/common/IDGen"
	"sanguo/node/node_game/module/role"
	"sanguo/node/node_game/user"
	table_Map "sanguo/node/table/excel/table/Map"
	cs_message "sanguo/protocol/cs/message"
	"strconv"
	"time"

	"github.com/go-redis/redis"
	"github.com/golang/protobuf/proto"
)

type transactionCreateRole struct {
	transaction.TransactionBase
	user    *user.User
	req     *codecs.Message
	resp    *cs_message.CreateRoleToC
	errcode cs_message.EnumType
}

func (this *transactionCreateRole) GetModuleName() string {
	return "CreateRole"
}

func (this *transactionCreateRole) GetReplyMsg() proto.Message {
	return &cs_message.CreateRoleToC{}
}

func (this *transactionCreateRole) SetExpiredTime(expired time.Time) {
	this.Expired = expired
}

func (this *transactionCreateRole) GetExpiredTime() time.Time {
	return this.Expired
}

func (this *transactionCreateRole) Begin() {
	node_game.Infoln(this.user.GetUserID(), "CreateRole ==>")
	this.resp = &cs_message.CreateRoleToC{}
	msg := this.req.GetData().(*cs_message.CreateRoleToS)
	roleModule := this.user.GetModuleByName("role").(*role.RoleModule)

	if roleModule.GetRoleCount() >= 3 {
		node_game.Infoln(this.user.GetUserID(), "CreateRole fail : Role Max Count")
		this.errcode = cs_message.EnumType_MAX_ROLE_COUNT
		this.user.EndTrans(this)
		return
	}

	roleID, err := IDGen.GenID()
	if nil != err {
		node_game.Infoln(this.user.GetUserID(), "CreateRole fail : role.GenID() err", err)
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}

	//验证名字合法性
	if wordsFilter.Check(msg.GetName()) {
		node_game.Infoln(this.user.GetUserID(), "CreateRole name is fail :", msg.GetName())
		this.errcode = cs_message.EnumType_ROLE_NAME_ERROR
		this.user.EndTrans(this)
		return
	}

	//验证名字唯一性
	this.CheckRoleName(roleID)
}

func (this *transactionCreateRole) CheckRoleName(roleID uint64) {

	msg := this.req.GetData().(*cs_message.CreateRoleToS)

	setCheckStr := `
		local rolename = redis.call('hget',KEYS[1],ARGV[1])
		if not rolename then
			redis.call('hset',KEYS[1],ARGV[1],ARGV[2])
			return 'ok'
		else
			return 'false'
		end
		`
	keys := []string{}
	keys = append(keys, "role_name_map")
	val := this.user.GetUserID() + ":" + strconv.FormatUint(roleID, 10)
	asynwrap.Wrap(db.GetRedisClient("game").Eval)(func(ret []interface{}) {
		if !this.user.CheckTrans(this) {
			this.HDelRoleName(msg.GetName())
			return
		}
		result, _ := ret[0].(*redis.Cmd).Result()
		if result.(string) == "ok" {
			this.CreateRole(roleID)
		} else if result.(string) == "false" {
			node_game.Infoln(this.user.GetUserID(), "createRole fail : Name repetition")
			this.errcode = cs_message.EnumType_ROLE_NAME_REPEATED
			this.user.EndTrans(this)
		}
	}, setCheckStr, keys, msg.GetName(), val)
}

func (this *transactionCreateRole) newRole(roleID uint64) *role.RoleData {
	//读表 初始等级
	level := int32(GlobalConstData.Level)
	mapID := int32(GlobalConstData.MapID)
	MapDef := table_Map.Table_.IDMap[mapID]

	msg := this.req.GetData().(*cs_message.CreateRoleToS)
	r := &role.RoleData{
		ID:         roleID,
		Lev:        level,
		Name:       msg.GetName(),
		Used:       0,
		Portrait:   msg.GetPortrait(),
		Face:       msg.GetFace(),
		Hair:       msg.GetHair(),
		HairColor:  msg.GetHairColor(),
		EyeColor:   msg.GetEyeColor(),
		Cloth:      msg.GetCloth(),
		ClothColor: msg.GetClothColor(),
		Weapon1:    100001,
		Weapon2:    0,
		AreaID:     this.user.GetEnterAreaID(),
		Outline:    msg.GetOutline(),
		MapID:      mapID,
		X:          MapDef.DefaultPosition.X,
		Y:          MapDef.DefaultPosition.Y,
		Z:          MapDef.DefaultPosition.Z,
		Angle:      MapDef.DefaultRotation,
	}
	return r
}

func (this *transactionCreateRole) CreateRole(roleID uint64) {
	//执行创角
	msg := this.req.GetData().(*cs_message.CreateRoleToS)
	roleModule := this.user.GetModuleByName("role").(*role.RoleModule)

	r := this.newRole(roleID)

	jsonStr, err := json.Marshal(r)
	if nil != err {
		node_game.Infoln(this.user.GetUserID(), "CreateRole fail : json.Marshal err", err)
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}
	key := "role:" + this.user.GetUserID()
	asynwrap.Wrap(db.GetRedisClient("game").HSet)(func(ret []interface{}) {
		if !this.user.CheckTrans(this) {

			node_game.Infoln(this.user.GetUserID(), "CreateRole fail : timeout")
			this.HDelRole(roleID)
			this.HDelRoleName(msg.GetName())
			return
		}
		_, err := ret[0].(*redis.BoolCmd).Result()
		if nil != err {
			node_game.Infoln(this.user.GetUserID(), "CreateRole fail : redis err", err)
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			this.HDelRoleName(msg.GetName())

		} else {
			if roleModule.AddRole(r) {
				rr := &cs_message.Role{
					ID:         proto.Uint64(r.ID),
					Lev:        proto.Int32(r.Lev),
					Name:       proto.String(r.Name),
					Used:       proto.Int32(r.Used),
					Portrait:   proto.Int32(r.Portrait),
					Face:       proto.Int32(r.Face),
					Hair:       proto.Int32(r.Hair),
					HairColor:  proto.Int32(r.HairColor),
					EyeColor:   proto.Int32(r.EyeColor),
					Cloth:      proto.Int32(r.Cloth),
					ClothColor: proto.Int32(r.ClothColor),
					Outline:    proto.Int32(r.Outline),
					Weapon1:    proto.Int32(r.Weapon1),
					Weapon2:    proto.Int32(r.Weapon2),
				}
				this.resp.NewRole = rr
				this.errcode = cs_message.EnumType_OK
				node_game.Infoln(this.user.GetUserID(), "CreateRole ok", r.ID)
				this.user.EndTrans(this)
			}
		}
	}, key, strconv.FormatUint(roleID, 10), jsonStr)
}

func (this *transactionCreateRole) HDelRoleName(roleName string) {
	//删除本次注册的rolename
	asynwrap.Wrap(db.GetRedisClient("game").HDel)(func(ret []interface{}) {
		_, err := ret[0].(*redis.IntCmd).Result()
		if err == nil {
			node_game.Infoln("CreateRole fail and Delete rolename ok ")
		} else {
			node_game.Infoln("CreateRole fail and Delete rolename error:", err)
		}
	}, "role_name_map", roleName)
}

func (this *transactionCreateRole) HDelRole(roleID uint64) {
	//删除本次注册的role
	key := "role:" + this.user.GetUserID()
	asynwrap.Wrap(db.GetRedisClient("game").HDel)(func(ret []interface{}) {
		_, err := ret[0].(*redis.IntCmd).Result()
		if err == nil {
			node_game.Infoln("CreateRole fail and Delete role ok ")
		} else {
			node_game.Infoln("CreateRole fail and Delete role error:", err)
		}
	}, key, strconv.FormatUint(roleID, 10))
}

func (this *transactionCreateRole) End() {
	if this.errcode == cs_message.EnumType_OK {
		roleModule := this.user.GetModuleByName("role").(*role.RoleModule)
		roleModule.ReportMaxLev()
		this.resp.Errcode = cs_message.EnumType(cs_message.EnumType_OK).Enum()
	} else {
		this.resp.Errcode = cs_message.EnumType(this.errcode).Enum()
	}
	this.user.Reply(this.req.GetSeriNo(), this.resp)
}

func (this *transactionCreateRole) Timeout() {
	this.resp.Errcode = cs_message.EnumType(cs_message.EnumType_RETRY).Enum()
	this.user.EndTrans(this)
}

func init() {
	user.RegisterTransFunc(&cs_message.CreateRoleToS{}, func(user *user.User, msg *codecs.Message) transaction.Transaction {
		return &transactionCreateRole{
			user: user,
			req:  msg,
		}
	})
}
